{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "54b1cd7d-e884-4d74-8a49-0fcdffdd3f30",
   "metadata": {},
   "source": [
    "# Exotic Options Pricing Models"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0bfc0241-b312-45cd-b1b6-cfecab9ad85e",
   "metadata": {},
   "source": [
    "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d0d0add-ff03-4c37-af3c-3942c8adc582",
   "metadata": {
    "tags": []
   },
   "source": [
    "## Load the Libs we need"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "4b0d19b3-7892-470c-8051-b3460605ed1a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# import Lib\n",
    "import pandas as pd\n",
    "import datetime as dt\n",
    "import pytz\n",
    "import os\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import yfinance as yf\n",
    "import scipy.stats as si\n",
    "import math\n",
    "import networkx as nx\n",
    "\n",
    "# import module\n",
    "from datetime import datetime, timezone\n",
    "from datetime import date, time\n",
    "from math import trunc\n",
    "from dateutil.parser import parse"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5649334c-a1a9-49f1-ab39-dff1bea2b512",
   "metadata": {},
   "source": [
    "## Implementing Exotic Options Pricing Models in Python"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "125c5a0a-8870-40db-bb9a-85feed23fcd5",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from scipy.stats import norm\n",
    "\n",
    "class mb_Option:\n",
    "    def __init__(self, spot_price, strike_price, risk_free_rate, volatility, maturity):\n",
    "        self.S = spot_price\n",
    "        self.K = strike_price\n",
    "        self.r = risk_free_rate\n",
    "        self.sigma = volatility\n",
    "        self.T = maturity\n",
    "\n",
    "class mb_BarrierOption(mb_Option):\n",
    "    def __init__(self, spot_price, strike_price, risk_free_rate, volatility, maturity, barrier_level):\n",
    "        super().__init__(spot_price, strike_price, risk_free_rate, volatility, maturity)\n",
    "        self.B = barrier_level\n",
    "\n",
    "    def mb_price_option(self, num_sims=10000):\n",
    "        payoff = 0\n",
    "        for _ in range(num_sims):\n",
    "            price_path = [self.S]\n",
    "            for _ in range(self.T):\n",
    "                price_path.append(\n",
    "                    price_path[-1] * np.exp((self.r - 0.5 * self.sigma**2) + self.sigma * np.random.standard_normal()))\n",
    "            payoff += max(0, max(price_path) - self.K) if max(price_path) > self.B else 0\n",
    "        return np.exp(-self.r * self.T) * (payoff / num_sims)\n",
    "\n",
    "class mb_AsianOption(mb_Option):\n",
    "    def mb_price_option(self, num_sims=10000):\n",
    "        payoff = 0\n",
    "        for _ in range(num_sims):\n",
    "            price_path = [self.S]\n",
    "            for _ in range(self.T):\n",
    "                price_path.append(\n",
    "                    price_path[-1] * np.exp((self.r - 0.5 * self.sigma**2) + self.sigma * np.random.standard_normal()))\n",
    "            average_price = np.mean(price_path)\n",
    "            payoff += max(0, average_price - self.K)\n",
    "        return np.exp(-self.r * self.T) * (payoff / num_sims)\n",
    "\n",
    "class mb_BinaryOption(mb_Option):\n",
    "    def mb_price_option(self):\n",
    "        d1 = (np.log(self.S / self.K) + (self.r + 0.5 * self.sigma ** 2) * self.T) / (self.sigma * np.sqrt(self.T))\n",
    "        d2 = d1 - self.sigma * np.sqrt(self.T)\n",
    "        return np.exp(-self.r * self.T) * norm.cdf(d2)\n",
    "\n",
    "class mb_LookbackOption(mb_Option):\n",
    "    def mb_price_option(self, num_sims=10000):\n",
    "        payoff = 0\n",
    "        for _ in range(num_sims):\n",
    "            price_path = [self.S]\n",
    "            for _ in range(self.T):\n",
    "                price_path.append(\n",
    "                    price_path[-1] * np.exp((self.r - 0.5 * self.sigma**2) + self.sigma * np.random.standard_normal()))\n",
    "            payoff += max(0, max(price_path) - self.K)\n",
    "        return np.exp(-self.r * self.T) * (payoff / num_sims)\n",
    "\n",
    "class mb_RainbowOption(mb_Option):\n",
    "    def __init__(self, spot_price1, spot_price2, strike_price, risk_free_rate, volatility1, volatility2, maturity, correlation):\n",
    "        super().__init__(spot_price1, strike_price, risk_free_rate, volatility1, maturity)\n",
    "        self.S2 = spot_price2\n",
    "        self.sigma2 = volatility2\n",
    "        self.rho = correlation\n",
    "\n",
    "    def mb_price_option(self, num_sims=10000):\n",
    "        payoff = 0\n",
    "        for _ in range(num_sims):\n",
    "            price_path1 = [self.S]\n",
    "            price_path2 = [self.S2]\n",
    "            for _ in range(self.T):\n",
    "                Z1 = np.random.standard_normal()\n",
    "                Z2 = self.rho * Z1 + np.sqrt(1 - self.rho**2) * np.random.standard_normal()\n",
    "                price_path1.append(price_path1[-1] * np.exp((self.r - 0.5 * self.sigma**2) + self.sigma * Z1))\n",
    "                price_path2.append(price_path2[-1] * np.exp((self.r - 0.5 * self.sigma2**2) + self.sigma2 * Z2))\n",
    "            payoff += max(0, max(price_path1[-1], price_path2[-1]) - self.K)\n",
    "        return np.exp(-self.r * self.T) * (payoff / num_sims)\n",
    "\n",
    "class mb_ChooserOption(mb_Option):\n",
    "    def __init__(self, spot_price, strike_price, risk_free_rate, volatility, maturity, choosing_time):\n",
    "        super().__init__(spot_price, strike_price, risk_free_rate, volatility, maturity)\n",
    "        self.t = choosing_time\n",
    "\n",
    "    def mb_price_option(self):\n",
    "        d1 = (np.log(self.S / self.K) + (self.r + 0.5 * self.sigma ** 2) * self.t) / (self.sigma * np.sqrt(self.t))\n",
    "        d2 = d1 - self.sigma * np.sqrt(self.t)\n",
    "        return self.S * norm.cdf(d1) - np.exp(-self.r * self.t) * self.K * norm.cdf(d2)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cd2d166b-5a29-4c09-8b8e-f6e55ffece05",
   "metadata": {},
   "source": [
    "#### Illustrative examples"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "e2abfd52-794e-4ff1-8301-badadc6e1c6e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Barrier Option Price: $10.18\n",
      "Asian Option Price: $4.33\n",
      "Binary Option Price: $0.41\n",
      "Lookback Option Price: $10.62\n",
      "Rainbow Option Price: $12.68\n",
      "Chooser Option Price: $6.63\n"
     ]
    }
   ],
   "source": [
    "# Define parameters\n",
    "S = 150  # Apple's current stock price\n",
    "K = 155  # Strike price\n",
    "r = 0.01  # Risk-free rate\n",
    "sigma = 0.2  # Volatility\n",
    "T = 1  # Time to maturity (in years)\n",
    "\n",
    "# Barrier Option\n",
    "B = 160  # Barrier level\n",
    "barrier_option = mb_BarrierOption(S, K, r, sigma, T, B)\n",
    "print(f\"Barrier Option Price: ${barrier_option.mb_price_option():.2f}\")\n",
    "\n",
    "# Asian Option\n",
    "asian_option = mb_AsianOption(S, K, r, sigma, T)\n",
    "print(f\"Asian Option Price: ${asian_option.mb_price_option():.2f}\")\n",
    "\n",
    "# Binary Option\n",
    "binary_option = mb_BinaryOption(S, K, r, sigma, T)\n",
    "print(f\"Binary Option Price: ${binary_option.mb_price_option():.2f}\")\n",
    "\n",
    "# Lookback Option\n",
    "lookback_option = mb_LookbackOption(S, K, r, sigma, T)\n",
    "print(f\"Lookback Option Price: ${lookback_option.mb_price_option():.2f}\")\n",
    "\n",
    "# Rainbow Option\n",
    "S2 = 140  # Price of a second stock\n",
    "sigma2 = 0.18  # Volatility of the second stock\n",
    "rho = 0.5  # Correlation between the two stocks\n",
    "rainbow_option = mb_RainbowOption(S, S2, K, r, sigma, sigma2, T, rho)\n",
    "print(f\"Rainbow Option Price: ${rainbow_option.mb_price_option():.2f}\")\n",
    "\n",
    "# Chooser Option\n",
    "t = 0.5  # Time at which the option type is chosen\n",
    "chooser_option = mb_ChooserOption(S, K, r, sigma, T, t)\n",
    "print(f\"Chooser Option Price: ${chooser_option.mb_price_option():.2f}\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "06ab27a0-f766-4a49-b805-92d135f5bc0c",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "37d27958-76fd-47ba-b6ee-6baa3b6fb9f6",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
